package com.cardone.persistent.aspect;

import com.cardone.common.cache.util.CacheUtils;
import com.cardone.context.ContextHolder;
import com.cardone.persistent.datasource.CardOneRoutingDataSource;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;

import java.util.Map;

/**
 * 路由拦截
 *
 * @author yaoht
 */
@lombok.Setter
@lombok.extern.slf4j.Slf4j
public class RouterDataSourceAspect {
    private String masterRouterKeyPrefix = "rw";
    private com.cardone.common.router.support.RouterKeySupport masterRouterKeySupport;
    private com.cardone.common.router.support.RouterKeySupport slaveRouterKeySupport;
    private com.cardone.common.router.support.RouterKeySupport determineCurrentLookupKeySupport;
    private Map<String, String> determineCurrentLookupKeyMap = com.google.common.collect.Maps.newConcurrentMap();

    public void clearCache(final org.aspectj.lang.JoinPoint joinPoint) {
        String determineCurrentLookupKey = CardOneRoutingDataSource.getDetermineCurrentLookupKey();

        if (StringUtils.isBlank(determineCurrentLookupKey) || StringUtils.startsWith(determineCurrentLookupKey, masterRouterKeyPrefix)) {
            Class<?>[] targetClasss = joinPoint.getTarget().getClass().getInterfaces();

            if (ArrayUtils.isEmpty(targetClasss)) {
                return;
            }

            for (Class<?> targetClass : targetClasss) {
                CacheUtils.clear(targetClass.getName());
            }
        }
    }

    private void setDetermineCurrentLookupKey(final org.aspectj.lang.JoinPoint joinPoint) {
        if ((determineCurrentLookupKeySupport == null) || (masterRouterKeySupport == null) || (slaveRouterKeySupport == null)) {
            return;
        }

        String key = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName();

        String determineCurrentLookupKey = determineCurrentLookupKeyMap.get(key);

        if (org.apache.commons.lang3.StringUtils.isNotBlank(determineCurrentLookupKey)) {
            CardOneRoutingDataSource.setDetermineCurrentLookupKey(determineCurrentLookupKey);

            if (log.isDebugEnabled()) {
                log.debug(key + ":determineCurrentLookupKey=" + determineCurrentLookupKey);
            }

            return;
        }

        String groupId;

        final java.lang.reflect.Method method = ((org.aspectj.lang.reflect.MethodSignature) joinPoint.getSignature()).getMethod();

        org.springframework.transaction.annotation.Transactional transactional = org.springframework.core.annotation.AnnotationUtils.findAnnotation(method, org.springframework.transaction.annotation.Transactional.class);

        if ((transactional == null) || transactional.readOnly()) {
            groupId = slaveRouterKeySupport.readKey(key);
        } else {
            groupId = masterRouterKeySupport.readKey(key);
        }

        if (log.isDebugEnabled()) {
            log.debug(key + ":groupId=" + groupId);
        }

        determineCurrentLookupKey = StringUtils.defaultString(determineCurrentLookupKeySupport.readKeyByGroupId(groupId, key), masterRouterKeyPrefix);

        CardOneRoutingDataSource.setDetermineCurrentLookupKey(determineCurrentLookupKey);

        determineCurrentLookupKeyMap.put(key, determineCurrentLookupKey);

        if (log.isDebugEnabled()) {
            log.debug(key + ":determineCurrentLookupKey=" + determineCurrentLookupKey);
        }
    }

    /**
     * 设置属性
     *
     * @param joinPoint 切片点
     */
    public Object setDetermineCurrentLookupKeyForProceed(final ProceedingJoinPoint joinPoint) throws Throwable {
        String determineCurrentLookupKey = CardOneRoutingDataSource.getDetermineCurrentLookupKey();

        if (StringUtils.startsWith(determineCurrentLookupKey, masterRouterKeyPrefix)) {
            return joinPoint.proceed();
        }

        this.setDetermineCurrentLookupKey(joinPoint);

        try {
            return joinPoint.proceed();
        } finally {
            CardOneRoutingDataSource.setDetermineCurrentLookupKey(null);
        }
    }
}
